<template>
  <div class="tree-map-chart" :class="{ 'show-btn': showBtn }" :style="style">
    <div v-if="showBtn" class="tag-list">
      <div v-for="(item, index) in tagList" :key="index" class="tag-item" @click="tagClick(index)">
        <div
          class="tag-sample"
          :style="{
            background: item.bgColor
          }"
        />
        <div class="tag-name">
          {{ item.label }}
        </div>
      </div>
    </div>
    <KCharts ref="treeMapChartRef" :width="width" :option="option" v-bind="$attrs" @click="handleItemClick" />
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue';
import { createTreeMapOption } from '@/hooks/charts/tree-map-chart';
import type { Options, BaseNameValueObject } from '@/hooks/charts/type';

defineOptions({ name: 'TreeMapChart' });

interface YData extends BaseNameValueObject {
  children?: YData[] | null;
}
interface Props {
  width: string;
  height: string;
  visualMap?: any;
  options?: Options;
  yData: YData[];
}
const props = withDefaults(defineProps<Props>(), {
  visualMap: {},
  options: () => {
    return {};
  }
});
const option = ref({});
const treeMapChartRef = ref();
const showBtn = ref<boolean>(false);
const style = computed(() => {
  return {
    width: props.width,
    height: props.height
  };
});
const tempDataByIndex = ref<Map<number, any>>(new Map());
const tagColors = ['var(--brand-6)', 'var(--pink-6)', 'var(--warning-6)'];
const levelColors = [
  ['#9EB2FA', '#869FF9', '#7D98F8', '#6E8CF7', '#6484F6', '#5679F6', '#4C71F6', '#3D65F5'],
  [
    'rgba(237, 124, 140, 0.45)',
    'rgba(237, 124, 140, 0.5)',
    'rgba(244, 176, 186, 1)',
    'rgba(237, 124, 140, 0.65)',
    'rgba(237, 124, 140, 0.7)',
    'rgba(241, 150, 163, 1)',
    'rgba(237, 124, 140, 0.9)',
    'rgba(237, 124, 140, 1)'
  ],
  [
    'rgba(236, 128, 61, 0.45)',
    'rgba(236, 128, 61, 0.5)',
    'rgba(244, 179, 139, 1)',
    'rgba(236, 128, 61, 0.65)',
    'rgba(236, 128, 61, 0.7)',
    'rgba(240, 153, 100, 1)',
    'rgba(236, 128, 61, 0.9)',
    'rgba(236, 128, 61, 1)'
  ]
];

let tagList = reactive<any[]>([]);

// 标签导航点击
const tagClick = (index: number) => {
  // 只有一个全部标签时不作处理
  if (tagList.length === 1) {
    return;
  }
  // 有多个标签的情况下，点击全部标签时，回到初始状态
  if (index === 0) {
    tagList = [];
    toNextLevel('全部', props.yData);
    return;
  } else if (index === 1) {
    if (tagList.length === 3) {
      tagList.pop();
    }
  }

  toLastLevel(index);
};

const tagsDict: any = {};

// 创建字典
const createTagsDict = (data: any[]) => {
  // 清空字典
  Object.keys(tagsDict).forEach((key) => {
    delete tagsDict[key];
  });
  // 重新创建字典
  data.forEach((item) => {
    tagsDict[item.name] = item.children;
  });
};

// 处理图表点击
const handleItemClick = (item: any) => {
  const key = item.data.name;
  const list = tagsDict[key];
  toNextLevel(item.name, list);
};

// 去上一层级
const toLastLevel = (index: number) => {
  const data = tempDataByIndex.value.get(index);
  createTagsDict(data);
  const sortData: any[] = data
    .map((item: any) => ({
      ...item,
      children: null
    }))
    .sort((a: any, b: any) => {
      return b.value - a.value;
    });

  option.value = createTreeMapOption({
    visualMap: {
      max: sortData[0].value,
      inRange: {
        color: levelColors[index]
      }
    },
    options: props.options ?? {},
    yData: sortData
  });
};

// 去下一层级
const toNextLevel = (tagName: string, data: any[]) => {
  if (!data?.length) {
    return;
  }

  // 将标签个数作为当前层级索引
  const index = tagList.length;
  // 创建字典
  createTagsDict(data);
  // 保存操作路径过程中每个层级的数据
  tempDataByIndex.value.set(index, data);
  // 排序后的图表数据
  const sortData: any[] = data
    .map((item: any) => ({
      ...item,
      children: null
    }))
    .sort((a: any, b: any) => {
      return b.value - a.value;
    });
  //  添加标签导航项
  tagList.push({ bgColor: tagColors[index], label: tagName });

  option.value = createTreeMapOption({
    visualMap: {
      max: sortData[0].value,
      inRange: {
        color: levelColors[index]
      }
    },
    options: props.options ?? {},
    yData: sortData
  });
};

watch(
  () => props.yData,
  () => {
    if (!props.yData.length) return;
    showBtn.value = props.yData.some((item: any) => item?.children?.length);
    tagList = [];
    toNextLevel('全部', props.yData);
  },
  {
    deep: true,
    immediate: true
  }
);
</script>

<style lang="scss" scoped>
.tree-map-chart {
  position: relative;
  box-sizing: border-box;

  &.show-btn {
    padding-top: 26px;
  }

  .tag-list {
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    align-items: center;
    width: 100%;
    height: 22px;
    padding: 0;

    .tag-item {
      position: relative;
      display: flex;
      align-items: center;
      margin-right: 20px;
      cursor: pointer;

      &:not(:first-child) {
        &::before {
          position: absolute;
          left: -18px;
          z-index: 999;
          width: 12px;
          height: 12px;
          cursor: default;
          content: '';
          background-image: url('@/assets/images/icons/line_arrow.svg');
          background-size: cover;
        }
      }
    }

    .tag-sample {
      width: 10px;
      height: 10px;
      margin-right: 6px;
      background-color: var(--brand-6);
    }

    .tag-name {
      font-size: 14px;
      line-height: 22px;
      color: var(--text-2-6);
    }
  }
}
</style>
